#include <ani.h>
#include <array>
#include <iostream>

static ani_object createPerson([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object){

    ani_object person_obj = {};

    //这里只能创建一个 Class 的实例，可以尝试改为 ani_interface/Person 会无法创建Object
    static const char *className = "ani_interface.PersonInner";
    ani_class cls;
    if (ANI_OK != env->FindClass(className, &cls)) {
        std::cerr << "Not found '" << className << "'" << std::endl;
        return person_obj;
    }

    //查找构造函数，如果没有重载，可以直接传递 nullptr
    ani_method ctor;
    if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)){
        std::cerr << "get ctor Failed'" << className << "'" << std::endl;
        return person_obj;
    }

    //创建一个 PersonInner 的实例
    if (ANI_OK != env->Object_New(cls, ctor, &person_obj)){
        std::cerr << "Create Object Failed'" << className << "'" << std::endl;
        return person_obj;
    }


    //Interface 及实现 Interface 中的成员都是 Property而不是 Field (参考spec, Interface Properties)
    //查找setter函数，当前FindSetter没实现，使用Class_FindMethod实现
    ani_method ageSetter;
    if(ANI_OK != env->Class_FindMethod(cls, "<set>age", nullptr, &ageSetter)){
        std::cerr << "Class_FindMethod Fail'" << className << "'" << std::endl;
    }

    if(ANI_OK != env->Object_CallMethod_Void(person_obj, ageSetter, ani_int(42)))
    {
        std::cerr << "Object_CallMethod_Void Fail'" << className << "'" << std::endl;
        return person_obj;
    }

    ani_method nameSetter;
    if(ANI_OK != env->Class_FindMethod(cls, "<set>name", nullptr, &nameSetter)){
        std::cerr << "Class_FindMethod Fail'" << "<set>name" << "'" << std::endl;
    }

    //从C++的string (大多数情况是UTF8) 构造一个 ani_string
    std::string name = "Goose";
    ani_string name_string{};

    env->String_NewUTF8(name.c_str(), name.size(), &name_string);

    //调用 set name(n:string)
    if(ANI_OK != env->Object_CallMethod_Void(person_obj, nameSetter, name_string))
    {
        std::cerr << "Object_CallMethod_Void Fail'" << className << "'" << std::endl;
        return person_obj;
    }

    return person_obj;
}

static ani_double getX([[maybe_unused]] ani_env *env, ani_object getObject){
    static const char *className = "Lani_interface/Point;";
    ani_class cls;
    if (ANI_OK != env->FindClass(className, &cls)) {
        std::cerr << "Not found '" << className << "'" << std::endl;
    }

    //Interface 及实现 Interface 中的成员都是 Property而不是 Field (参考spec, Interface Properties)
    ani_method ageGetter;
    if(ANI_OK != env->Class_FindGetter(cls, "x",  &ageGetter)){
        std::cerr << "Class_FindMethod Fail'" << className << "'" << std::endl;
    }
    ani_double rs;
    if(ANI_OK != env->Object_CallMethod_Double(getObject, ageGetter, &rs))
    {
        std::cerr << "Object_CallMethod_Void Fail'" << className << "'" << std::endl;
    }

    return rs;
}

ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
{
    ani_env *env;
    if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
        std::cerr << "Unsupported ANI_VERSION_1" << std::endl;
        return ANI_ERROR;
    }

    static const char *moduleName = "ani_interface";
   
    ani_module module;
    if (ANI_OK != env->FindModule(moduleName, &module)) {
        std::cerr << "Not found '" << moduleName << "'" << std::endl;
        return ANI_ERROR;
    }

    std::array methods = {
        ani_native_function {"createPerson", nullptr, reinterpret_cast<void *>(createPerson)},
        ani_native_function {"getX", nullptr, reinterpret_cast<void *>(getX)},
    };

    std::cout << "Start bind native methods to '" << moduleName << "'" << std::endl;

    if (ANI_OK != env->Module_BindNativeFunctions(module, methods.data(), methods.size())) {
        std::cerr << "Cannot bind native methods to '" << moduleName << "'" << std::endl;
        return ANI_ERROR;
    };
    std::cout << "Finish bind native methods to '" << moduleName << "'" << std::endl;

    *result = ANI_VERSION_1;
    return ANI_OK;
}